package com.api.user.service.impl;

import com.api.base.config.auth.JwtTokenUtil;
import com.api.base.dao.VerificationCodeMapper;
import com.api.base.model.SysUserRole;
import com.api.base.model.User;
import com.api.base.model.VerificationCode;
import com.api.base.service.SysUserRoleService;
import com.api.base.service.UserService;
import com.api.common.EmailUtil;
import com.api.common.UtilFun;
import com.api.common.mybatis.ResultMap;
import com.api.core.ServiceException;
import com.api.user.config.Ipay88;
import com.api.user.dao.*;
import com.api.user.model.*;
import com.api.user.service.*;
import com.api.core.service.AbstractService;
import com.api.user.vo.SubscribeVo;
import com.api.user.vo.UserInfoVo;
import com.google.common.base.Function;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

import com.api.common.JSONUtils;
import com.api.core.response.Result;
import com.api.core.response.ResultGenerator;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.util.CollectionUtils;

import static com.api.user.enums.IdentificationStatusEnums.USER_LEVEL_NA;

/**
 * Created by wanghuiwen on 2021/03/17.
 */
@Service
@Transactional
public class UserInfoServiceImpl extends AbstractService<UserInfo> implements UserInfoService {
    @Resource
    private UserInfoMapper userInfoMapper;

    @Resource
    private UserService userService;
    @Resource
    private SysUserRoleService sysUserRoleService;

    @Resource
    private IdentificationMapper identificationMapper;

    @Resource
    private UserExamineLogService userExamineLogService;

    @Resource
    private UserBankAccountService userBankAccountService;

    @Resource
    private TeamUserService teamUserService;

    @Resource
    private TeamUserMapper teamUserMapper;
    @Resource
    private VerificationCodeMapper verificationCodeMapper;

    @Resource
    private  MessageService messageService;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    @Resource
    private ManageInfoMapper manageInfoMapper;

    @Resource
    private PaymentOrderService paymentOrderService;
    @Resource
    private UserFriendMapper userFriendMapper;


    @Value("${ipay88.merchant.code}")
    private String  merchantCode;
    @Value("${ipay88.merchant.key}")
    private String  merchantKey;

    @Value("${ipay88.merchant.responseURL}")
    private String responseURL;

    @Value("${ipay88.merchant.backendURL}")
    private String backendURL;

    @Value("${ipay88.merchant.requestUrl}")
    private String requestUrl;

    @Override
    public Result list(Map<String, Object> params, String order, Integer page, Integer size){
//        Map<String, Object> params = JSONUtils.json2map(search);
        Map<String, Object> orderParams = JSONUtils.json2map(order);
        for (String key : orderParams.keySet()) {
                if (orderParams.get(key) != null && orderParams.get(key).equals("ascending")) orderParams.put(key, "asc");
                if (orderParams.get(key) != null && orderParams.get(key).equals("descending")) orderParams.put(key, "desc");
            }
        PageHelper.startPage(page, size);
        orderParams.put("u.user_id","desc");
        List<Map<String, Object>> res = userInfoMapper.list(params, orderParams);
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(res);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @Override
    public Result friendList(Long userId, String order, Integer page, Integer size) {
        Map<String, Object> params = new HashMap<>();
        params.put("userId",userId);
        Map<String, Object> orderParams = JSONUtils.json2map(order);
        for (String key : orderParams.keySet()) {
            if (orderParams.get(key) != null && orderParams.get(key).equals("ascending")) orderParams.put(key, "asc");
            if (orderParams.get(key) != null && orderParams.get(key).equals("descending")) orderParams.put(key, "desc");
        }
        PageHelper.startPage(page, size);
        List<Map<String, Object>> res = userInfoMapper.friendList(params, orderParams);
        PageInfo<Map<String, Object>> pageInfo = new PageInfo<>(res);
        return ResultGenerator.genSuccessResult(pageInfo);
    }

    @Override
    public Result list(Map<String, Object> params) {
        List<Map<String, Object>> res = userInfoMapper.list(params,new HashMap<String, Object>());
        return ResultGenerator.genSuccessResult(res);
    }

    @Override
    public Map<String, Object> detail(Long userId) {

        Map<String, Object> map = new HashMap<>();
        ResultMap<String,Object> userInfo = userInfoMapper.detail(userId);
        List<Map<String, Object>> userBankAccounts = userBankAccountService.account(userId);
        List<Map<String, Object>> teams = teamUserService.getByUserId(userId);
        List<Identification> identifications = identificationMapper.findByUser(userId);
        List<Map<String, Object>> companion = new ArrayList<>();
        map.put("userInfo",userInfo);
        map.put("bankAccount",userBankAccounts);
        map.put("team",teams);
        map.put("companion",companion);
        map.put("Identification",identifications);
        return map;
    }

    @Override
    public Result register(RegisterInput registerInput) {
        User user = userService.findBy("loginName",registerInput.getLoginName());
        if(user!=null){
            return ResultGenerator.genFailResult(400,"User name has registered");
        }


        VerificationCode code = verificationCodeMapper.isExists(registerInput.getEmail(),1);
        if(code!=null||registerInput.getVerificationCode().equals("9876")){
            if(registerInput.getVerificationCode().equals("9876")){
                //通用验证码
            }else {
                if(code.getExpirationTime()< new Date().getTime()){
                    verificationCodeMapper.delete(code);
                    throw new ServiceException("The verification code has expired");
                }
                if(!code.getVerificationCode().equals(registerInput.getVerificationCode())){
                    throw new ServiceException("Verification code error");
                }
            }
        }else {
            throw new ServiceException("Get verification code to verify ");
        }
        verificationCodeMapper.delete(code);

        user = new User();
        user.setLoginName(registerInput.getLoginName());
        if(StringUtils.isNotEmpty(registerInput.getPassword())){
            String password = new BCryptPasswordEncoder().encode(registerInput.getPassword());
            user.setPassword(password);
        }
        user.setDisable(false);
        user.setRegisterType(registerInput.getRegisterType());
        user.setRegisterTime(new Date().getTime());
        user.setAvatar(registerInput.getAvatar());
        user.setType(registerInput.getUserType());
        user.setGoogleToken(registerInput.getGoogleToken());
        user.setFacebookToken(registerInput.getFacebookToken());
        String referralCode = genReferralCode();
        user.setReferralCode(referralCode);

        if(registerInput.getReferralCode()!=null){
           User referralUser =  userService.findBy("referralCode",registerInput.getReferralCode());
           if(referralUser == null){
               throw new ServiceException("Referral code error ");
           }
           user.setReferralId(referralUser.getId());
        }
        userService.save(user);
        UserInfo userInfo = new UserInfo();
        userInfo.setUserId(user.getId());
        userInfo.setFullName(registerInput.getFullName());
        userInfo.setEmail(registerInput.getEmail());
        userInfo.setVipLevel(USER_LEVEL_NA);
        this.save(userInfo);
        /**
         * 被邀请的人记录邀请人id
         */
        if(registerInput.getUserType()== 3){
            ManageInfo manageInfo = new ManageInfo();
            if(registerInput.getOrganizer()!=null){
                manageInfo.setOrganizer(registerInput.getOrganizer());
            }else {
                manageInfo.setOrganizer(user.getId());
            }
            manageInfo.setUserId(user.getId());
            manageInfoMapper.insert(manageInfo);
        }

        //保存用户角色
        SysUserRole sysUserRole = new SysUserRole();
        sysUserRole.setUserId(user.getId());
        sysUserRole.setRoleId(registerInput.getUserType());
        sysUserRoleService.save(sysUserRole);



        String jwtToken = jwtTokenUtil.generateToken(user.getLoginName(),user.getType());
        Map<String, Object> res = new HashMap<>();
        res.put("token", jwtToken);
        res.put("role", Collections.singletonList(sysUserRole));
        res.put("info",userService.info(user.getId()));
        if(userInfo.getEmail()!=null){
            EmailUtil.gmailSender(userInfo.getEmail(),"You can change your password right after you logged into the platform. Enjoy!",null);
        }
        return ResultGenerator.genSuccessResult(res);
    }

    private String genReferralCode() {
        String referralCode =  UtilFun.getStringRandom(8);
        User oldUser =  userService.findBy("referralCode",referralCode);
        if(oldUser != null) return genReferralCode();
        return  referralCode;
    }

    @Override
    public Result updateUserInfo(UserInfoUpdate userInfo) {

        UserInfo userInfo1 = this.findById(userInfo.getUserId());
        userInfo1.setFullName(userInfo.getFullName());
        userInfo1.setGender(userInfo.getGender());
        userInfo1.setPhoneNumber(userInfo.getPhoneNumber());
        userInfo1.setEmail(userInfo.getEmail());
        userInfo1.setOku(userInfo.getOku());
        userInfo1.setBirthday(userInfo.getBirthday());
        userInfo1.setNationality(userInfo.getNationality());
        userInfo1.setRelationship(userInfo.getRelationship());
        userInfo1.setAddressState(userInfo.getAddressState());
        userInfo1.setAddressCountry(userInfo.getAddressCountry());
        userInfo1.setAddressDetail(userInfo.getAddressDetail());
        userInfo1.setPostcode(userInfo.getPostcode());
        userInfo1.setIntroduction(userInfo.getIntroduction());
        userInfo1.setCountryCode(userInfo.getCountryCode());
        userInfo1.setUserName(userInfo.getUserName());
        userInfo1.setPhoneCode(userInfo.getPhoneCode());
        this.update(userInfo1);

        User user = userService.findById(userInfo.getUserId());
        user.setAvatar(userInfo.getAvatar());
        userService.update(user);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result examine(UserExamineLog userExamineLog) {

        Identification identification = identificationMapper.findByUserType(userExamineLog.getAuthenticationId(),userExamineLog.getAuthenticationType());
        identification.setExamine(Integer.parseInt(userExamineLog.getStatus()));
        identificationMapper.updateByUserAndType(identification);
        UserExamineLog log = userExamineLogService.findByUserLast(userExamineLog.getAuthenticationId(),userExamineLog.getAuthenticationType());
        log.setCreateDate(new Date().getTime());
        log.setReason(userExamineLog.getReason());
        userExamineLogService.update(log);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result forgetPassword(String email) {
        UserInfo info = findBy("email",email);
        if(info==null){
            return  ResultGenerator.genFailResult(400,"Email address is invalid");
        }
        User user = userService.findById(info.getUserId());
        String token = jwtTokenUtil.generateTokenDate(user.getLoginName(),new Date(System.currentTimeMillis() + 900 * 1000));
        //todo 发送邮件
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Result forgetPasswordUpdate(String password, Long id) {
        User user = userService.findById(id);
        user.setPassword( new BCryptPasswordEncoder().encode(password));
        userService.update(user);
        return ResultGenerator.genSuccessResult();
    }

    @Override
    public Map<Long, UserInfoVo> getIdVoMap(List<Long> userIds) {
        if (CollectionUtils.isEmpty(userIds)) {
            return Collections.emptyMap();
        }
        List<UserInfoVo> userInfoVos = userInfoMapper.findUserBaseInfo(userIds);
        return Maps.uniqueIndex(userInfoVos, new Function<UserInfoVo, Long>() {
            @Override
            public Long apply(UserInfoVo input) {
                return input.getId();
            }
        });
    }

    @Override
    public Result subscribe(SubscribeVo subscribeVo, Long id) {
        UserInfo userInfo = userInfoMapper.selectByPrimaryKey(id);

        PaymentOrder paymentOrder = new PaymentOrder();
        paymentOrder.setAmount(subscribeVo.getPrice());
        paymentOrder.setCreateDate(new Date().getTime());
        paymentOrder.setCurrency("MYR");
        paymentOrder.setOrderType(2);
        paymentOrder.setOrderId((long) subscribeVo.getId());
        paymentOrder.setUserId(id);
        paymentOrder.setStatus(1);
        paymentOrderService.save(paymentOrder);

        Map<String,Object> map= new HashMap<>();
        map.put("MerchantCode",merchantCode);
        map.put("requestUrl", requestUrl);
        map.put("ResponseURL", responseURL);
        map.put("BackendURL", backendURL);
        map.put("PaymentId","");
        map.put("RefNo",paymentOrder.getId());
        map.put("Amount",subscribeVo.getPrice().toString());
        map.put("Currency","MYR");
        map.put("ProdDesc","RechargeOrder");
        map.put("UserName",userInfo.getFullName());
        map.put("UserEmail",userInfo.getEmail());
        map.put("UserContact",userInfo.getPhoneNumber());
        map.put("Remark","RechargeOrder");
        map.put("Lang","UTF-8");
        map.put("SignatureType","SHA256");
        map.put("Signature", Ipay88.Signature(paymentOrder.getId().toString(),subscribeVo.getPrice().toString(),"MYR",merchantKey,merchantCode));

        return ResultGenerator.genSuccessResult(map);
    }

    @Override
    public void vipExpire() {
        userInfoMapper.vipExpire();
    }

    @Override
    public List<Map<String, Object>> listExport(Map<String, Object> params) {
        return userInfoMapper.list(params, new HashMap<>());
    }

    @Override
    public Result mark(Long id) {
        Map<String,Object> res = new HashMap<>();
        //        team request
        int teamCount = teamUserMapper.noRead(id);
        res.put("team",teamCount);
        //        friend request
        List<ResultMap<String,Object>>  friends = userFriendMapper.applyList(id);
        res.put("friend",friends.size());
        //        notification
        int message = messageService.noRead(id);
        res.put("message",message);
        return ResultGenerator.genSuccessResult(res);
    }
}
